package org.smallreunion.controller;

import java.util.logging.Level;
import java.util.logging.Logger;

import javax.servlet.http.Cookie;

import org.slim3.controller.Controller;
import org.slim3.controller.Navigation;
import org.smallreunion.exception.NotLoginRuntimeException;
import org.smallreunion.helper.LoginViewHelper;
import org.smallreunion.service.AuthTokenService;
import org.smallreunion.util.StringUtil;
import org.smallreunion.var.LoginInfo;

/**
 * AbstractController
 *
 * @author Sinmetal
 *
 */
public abstract class AbstractController extends Controller {

    public final String SESSION_TOKEN = "sessionToken";
    public final String AUTH_TOKEN = "authToken";
    /** AutoLogin用DefaultTimeout */
    public final int DEFAULT_TIMEOUT = 30 * 60;

    private AuthTokenService authTokenService = new AuthTokenService();

    private static final Logger logger = Logger
        .getLogger(AbstractController.class.getName());

    /**
     * 全ページで必要な情報を設定
     *
     */
    @Override
    protected Navigation setUp() {
        LoginInfo loginInfo = getLoginInfo();
        requestScope("loginViewHelper", LoginViewHelper.getInstance(loginInfo));
        return null;
    }

    /**
     * Session から ログイン情報を取得
     *
     * @return
     */
    protected LoginInfo getLoginInfo() {
        String token = getAuthToken();
        if (StringUtil.isEmpty(token)) {
            return null;
        }

        LoginInfo loginInfo;
        loginInfo = authTokenService.getLoginInfoInMemory(token);
        if (loginInfo != null) {
            logger.log(Level.INFO, "auth token find memory");
            return loginInfo;
        }

        loginInfo = authTokenService.getLoginInfo(token);
        if (loginInfo != null) {
            logger.log(Level.INFO, "auth token find datastore");
            authTokenService.deleteAuthToken(token);
            entryAuthToken(loginInfo, true);
            return loginInfo;
        }
        return null;
    }

    /**
     * entry auth token to cookie with datastore
     *
     * @param member
     * @param autoLogin
     */
    protected void entryAuthToken(LoginInfo loginInfo, boolean autoLogin) {
        String token =
            authTokenService.createAuthTokenString(loginInfo.getKey());

        Integer timeout = DEFAULT_TIMEOUT;
        if (autoLogin) {
            final int WEEK_SEC = 7 * 24 * 60 * 60;
            timeout = WEEK_SEC;
        }
        authTokenService.putLoginInfo(token, loginInfo, timeout);
        setAuthToken(token, timeout);
    }

    /**
     * ログイン情報から、TwitterIDを取得
     *
     * @return
     */
    protected long getTwitterId() {
        LoginInfo loginInfo = getLoginInfo();
        if (loginInfo == null) {
            throw new NotLoginRuntimeException();
        }
        return loginInfo.getTwitterId();
    }

    /**
     * ログアウトを行う
     */
    protected void logout() {
        String token = getAuthToken();
        if (StringUtil.isEmpty(token)) {
            return;
        }
        authTokenService.deleteAuthToken(token);
    }

    /**
     * get session token in cookie
     *
     * @return
     */
    protected String getSessionToken() {
        return getToken(SESSION_TOKEN);
    }

    /**
     * set session token to cookie
     *
     * @param token
     */
    protected void setSessionToken(String token) {
        Cookie cookie = new Cookie(SESSION_TOKEN, token);
        cookie.setPath("/");
        response.addCookie(cookie);
    }

    /**
     * get auth token int cookie
     *
     * @return
     */
    protected String getAuthToken() {
        return getToken(AUTH_TOKEN);
    }

    /**
     * set auth token to cookie
     *
     * @param token
     * @param maxAge
     */
    protected void setAuthToken(String token, int maxAge) {
        Cookie cookie = new Cookie(AUTH_TOKEN, token);
        cookie.setMaxAge(maxAge);
        cookie.setPath("/");
        response.addCookie(cookie);
    }

    /**
     * get token in cookie
     *
     * @param key
     * @return
     */
    private String getToken(String key) {
        Cookie[] cookies = request.getCookies();
        if (cookies == null) {
            return "";
        }
        for (Cookie cookie : cookies) {
            if (cookie.getName().equals(key)) {
                return cookie.getValue();
            }
        }
        return "";
    }
}
